﻿/*
 * Author: Mattan360
 * Contributors:
 */

using System;
using System.Runtime.InteropServices;
using Irrlicht.Net.Core;
using Irrlicht.Net.IO;
using Irrlicht.Net.Video;

namespace Irrlicht.Net.Scene
{
    public class SceneNode : AttributeExchangingObject
    {
        #region PInvoke
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_AddAnimator(IntPtr node, IntPtr animator);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_AddChild(IntPtr node, IntPtr child);

        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern IntPtr SceneNode_Clone(IntPtr node, IntPtr? newParent, IntPtr? newManager);

        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_GetAbsolutePosition(IntPtr node, ref float x, ref float y, ref float z);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern uint SceneNode_GetAutomaticCulling(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern int SceneNode_GetID(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern IntPtr SceneNode_GetMaterial(IntPtr node, uint num);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern uint SceneNode_GetMaterialCount(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern IntPtr SceneNode_GetName(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern IntPtr SceneNode_GetParent(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_GetPosition(IntPtr node, ref float x, ref float y, ref float z);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_GetRotation(IntPtr node, ref float x, ref float y, ref float z);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_GetScale(IntPtr node, ref float x, ref float y, ref float z);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern IntPtr SceneNode_GetSceneManager(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern IntPtr SceneNode_GetTriangleSelector(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern uint SceneNode_GetType(IntPtr node);

        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern int SceneNode_IsDebugDataVisible(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern bool SceneNode_IsDebugObject(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern bool SceneNode_IsTrulyVisible(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern bool SceneNode_IsVisible(IntPtr node);

        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_OnAnimate(IntPtr node, uint time);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_OnRegisterSceneNode(IntPtr node);

        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_Remove(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_RemoveAll(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_RemoveAnimator(IntPtr node, IntPtr animator);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_RemoveAnimators(IntPtr node);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_RemoveChild(IntPtr node, IntPtr child);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_Render(IntPtr node);

        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetAutomaticCulling(IntPtr node, uint culling);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetDebugDataVisible(IntPtr node, int state);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetID(IntPtr node, int id);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetIsDebugObject(IntPtr node, bool debugObject);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetMaterialFlag(IntPtr node, int flag, bool value);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetMaterialTexture(IntPtr node, int textureLayer, IntPtr texture);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetName(IntPtr node,
            [MarshalAs(UnmanagedType.AnsiBStr)]
            string name);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetParent(IntPtr node, IntPtr parent);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetPosition(IntPtr node, float x, float y, float z);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetRotation(IntPtr node, float x, float y, float z);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetScale(IntPtr node, float x, float y, float z);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetTrianlgeSelector(IntPtr node, IntPtr selector);
        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_SetVisible(IntPtr node, bool visible);

        [DllImport("IrrlichtW.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void SceneNode_UpdateAbsolutePosition(IntPtr node);
        #endregion

        public SceneNode(IntPtr pointer)
        {
            this.pointer = pointer;
        }

        public void AddAnimator(SceneNodeAnimator animator)
        {
            SceneNode_AddAnimator(pointer, animator.pointer);
        }

        public void AddChild(SceneNode child)
        {
            SceneNode_AddChild(pointer, child.pointer);
        }

        public SceneNode Clone()
        {
            return new SceneNode(SceneNode_Clone(pointer, null, null));
        }

        public SceneNode Clone(SceneNode newParent)
        {
            return new SceneNode(SceneNode_Clone(pointer, newParent.pointer, null));
        }

        public SceneNode Clone(SceneManager newManager)
        {
            return new SceneNode(SceneNode_Clone(pointer, null, newManager.pointer));
        }

        public SceneNode Clone(SceneNode newParent, SceneManager newManager)
        {
            return new SceneNode(SceneNode_Clone(pointer, newParent.pointer, newManager.pointer));
        }

        public Vector3D AbsolutePosition
        {
            get
            {
                float x = 0, y = 0, z = 0;
                SceneNode_GetAbsolutePosition(pointer, ref x, ref y, ref z);
                return new Vector3D(x, y, z);
            }
        }

        public Vector3D Position
        {
            get
            {
                float x = 0, y = 0, z = 0;
                SceneNode_GetPosition(pointer, ref x, ref y, ref z);
                return new Vector3D(x, y, z);
            }

            set
            {
                Vector3D pos = value;
                SceneNode_SetPosition(pointer, pos.x, pos.y, pos.z);
            }
        }

        public Vector3D Rotation
        {
            get
            {
                float x = 0, y = 0, z = 0;
                SceneNode_GetRotation(pointer, ref x, ref y, ref z);
                return new Vector3D(x, y, z);
            }

            set
            {
                Vector3D rot = value;
                SceneNode_SetRotation(pointer, rot.x, rot.y, rot.z);
            }
        }

        public Vector3D Scale
        {
            get
            {
                float x = 0, y = 0, z = 0;
                SceneNode_GetScale(pointer, ref x, ref y, ref z);
                return new Vector3D(x, y, z);
            }

            set
            {
                Vector3D scale = value;
                SceneNode_SetScale(pointer, scale.x, scale.y, scale.z);
            }
        }

        public CullingType AutomaticCulling
        {
            get
            {
                return (CullingType)SceneNode_GetAutomaticCulling(pointer);
            }
            set
            {
                SceneNode_SetAutomaticCulling(pointer, (uint)value);
            }
        }

        public int ID
        {
            get
            {
                return SceneNode_GetID(pointer);
            }
            set
            {
                SceneNode_SetID(pointer, value);
            }
        }

        public uint MaterialCount
        {
            get
            {
                return SceneNode_GetMaterialCount(pointer);
            }
        }

        public string Name
        {
            get
            {
                IntPtr name = SceneNode_GetName(pointer);
                return Marshal.PtrToStringAnsi(name);
            }
            set
            {
                SceneNode_SetName(pointer, value);
            }
        }

        public SceneNode Parent
        {
            get
            {
                return new SceneNode(SceneNode_GetParent(pointer));
            }
            set
            {
                SceneNode_SetParent(pointer, value.pointer);
            }
        }

        public ReferenceCounted TriangleSelector
        {
            get
            {
                return new ReferenceCounted(SceneNode_GetTriangleSelector(pointer));
            }
            set
            {
                SceneNode_SetTrianlgeSelector(pointer, value.pointer);
            }
        }

        public uint Type
        {
            get
            {
                return SceneNode_GetType(pointer);
            }
        }

        public int IsDebugDataVisible
        {
            get
            {
                return SceneNode_IsDebugDataVisible(pointer);
            }
            set
            {
                SceneNode_SetDebugDataVisible(pointer, value);
            }
        }

        public bool IsDebugObject
        {
            get
            {
                return SceneNode_IsDebugObject(pointer);
            }
            set
            {
                SceneNode_SetIsDebugObject(pointer, value);
            }
        }
        public bool IsTrulyVisible
        {
            get
            {
                return SceneNode_IsTrulyVisible(pointer);
            }
        }
        public bool IsVisible
        {
            get
            {
                return SceneNode_IsVisible(pointer);
            }
            set
            {
                SceneNode_SetVisible(pointer, value);
            }
        }

        public Material GetMaterial(uint num)
        {
            return new Material(SceneNode_GetMaterial(pointer, num));
        }

        public void SetMaterialFlag(MaterialFlags flag, bool value)
        {
            SceneNode_SetMaterialFlag(pointer, (int)flag, value);
        }
        public void SetMaterialTexture(int textureLayer, Texture texture)
        {
            SceneNode_SetMaterialTexture(pointer, textureLayer, texture.pointer);
        }

        public void Remove()
        {
            SceneNode_Remove(pointer);
        }
        public void RemoveAll()
        {
            SceneNode_RemoveAll(pointer);
        }

        //public void RemoveAnimator(IntPtr animator)
        public void RemoveAnimator(SceneNodeAnimator animator)
        {
            SceneNode_RemoveAnimator(pointer, animator.pointer);
        }

        public void RemoveAnimators()
        {
            SceneNode_RemoveAnimators(pointer);
        }

        public void RemoveChild(SceneNode child)
        {
            SceneNode_RemoveChild(pointer, child.pointer);
        }

        public void Render()
        {
            SceneNode_Render(pointer);
        }

        public void UpdateAbsolutePosition()
        {
            SceneNode_UpdateAbsolutePosition(pointer);
        }
    }
}
